package Model
{
	import Controller.AreasController;
	
	[Bindable]
	public class Calculations
	{
		private var _transmissionHeatLosses:Number = 0;
		private var _ventilationHeatLosses:Number = 0;
		private var _totalHeatLosses:Number = 0;
		private var _internalHeatGains:Number = 0;
		private var _solarHeatGains:Number = 0;
		private var _totalHeatGains:Number = 0;
		private var _anualHeatDemand:Number = 0;
		private var _specificAnnualHeatDemand:Number = 0;
		
		private var areasController:AreasController;
		
		public function Calculations()
		{
			this.areasController = new AreasController();
		}
		
		public function calculate(data:Project):void
		{
			this.transmissionHeatLosses = calculateTransmissionHeatLosses(data.projectInfo.climateZone.gt);
			this.ventilationHeatLosses = calculateVentilationHeatLosses(data.projectInfo.climateZone.gt, data.heating, data.quality);
			this.totalHeatLosses = calculateTotalHeatLosses();
			this.internalHeatGains = calcuclateInternalHeatGains(data.projectInfo.climateZone.ht);
			this.solarHeatGains = calculateSolarHeatGains(data.projectInfo.climateZone, data.areas);
			this.totalHeatGains = calculateTotalHeatGains();
			this.anualHeatDemand =calculateAnnualHeatDemand();
			this.specificAnnualHeatDemand = calculateSpecificAnnualHeatDemand();
		}
		
		private function calculateTransmissionHeatLosses(heatingHours:Number):Number
		{
			var heatLossesFromWallsAgainstAir:Number =  calculateHeateLossesByComponentType("Wall against air",heatingHours);
			var heatLossesFromWallsAgainstGround:Number =  calculateHeateLossesByComponentType("Wall against ground",heatingHours);
			var heatLossesFromFlatRoofs:Number =  calculateHeateLossesByComponentType("Roof flat",heatingHours);
			var heatLossesFromSloppedRoofs:Number =  calculateHeateLossesByComponentType("Pitched roof/mono pitched",heatingHours);
			var heatLossesFromFloorSlabsAgainstUnheatedCellar:Number =  calculateHeateLossesByComponentType("Slab against unheated cellar",heatingHours);
			var heatLossesFromFloorSlabsAgainstGround:Number =  calculateHeateLossesByComponentType("Slab against ground",heatingHours);
			var heatLossesFromDoors:Number =  calculateHeateLossesByDoors(heatingHours);
			var heatLossesFromWindows:Number = calculateHeateLossesByWindows(heatingHours);
			
			var heatLossesFromThermalBridges:Number  = (0.4 * this.areasController.getThermalEnvelopeArea()) * (-0.01) * 1 * heatingHours;
			
			return heatLossesFromWallsAgainstAir + heatLossesFromFloorSlabsAgainstGround + heatLossesFromSloppedRoofs 
				+ heatLossesFromFlatRoofs + heatLossesFromFloorSlabsAgainstUnheatedCellar + heatLossesFromFloorSlabsAgainstGround + 
				heatLossesFromWindows + heatLossesFromThermalBridges;
		}
		
		private function calculateVentilationHeatLosses(heatingHours:Number ,heatingData:HeatingInfo, qualityData:Quality):Number
		{
			var efficiencyOfHeatRecoverySystem:Number = heatingData.heatRecoverySystem.efficiency/100;
			var efficiencyOfSubsoilHeatExchanger:Number = heatingData.subsoilHeatExchanger.efficiency/100;
			var airtightnessRate:Number = qualityData.airtightnessRate;
			var windScreen:Number = 0.07;
			var vn50vv:Number = 1;
			
			//First row of calculation
			var airExchangeLosses:Number = airtightnessRate * windScreen * vn50vv;
			
			var meanAirExchangeHeatRecovery:Number = 0.4;
			var effectivenessOfHeatRecovery:Number =  1 - (1 - efficiencyOfHeatRecoverySystem )
			
			//second row of calculation
			var energeticallyEfficiencyOfAirExchange:Number = (meanAirExchangeHeatRecovery * effectivenessOfHeatRecovery) + airExchangeLosses;
				
			//third row of caluclations
			var heatedSpaceVolume:Number = this.areasController.getTotalHeatedSpaceVolume();
			
			return heatedSpaceVolume * energeticallyEfficiencyOfAirExchange * 0.33 * heatingHours;
		}
		
		private function calculateTotalHeatLosses():Number
		{
			return this.transmissionHeatLosses + this.ventilationHeatLosses;
		}
		
		private function calcuclateInternalHeatGains(lengthOfHeatingPeriod:Number):Number
		{
			var khd:Number = 0.024;
			var specPowerBasedOnUse:Number = 2.10;
			var heatedSpaceArea:Number = this.areasController.getTotlaHeatedSpaceArea();
			
			return khd * lengthOfHeatingPeriod * specPowerBasedOnUse * heatedSpaceArea;
		}
		
		private function calculateSolarHeatGains(climateZoneInfo:ClimateZone, areas:Areas):Number
		{
			var areaGlazingNorth:Number = areas.calculateTotalWindowsAreaByOrientation("North");
			var areaGlazingNorthEast:Number = areas.calculateTotalWindowsAreaByOrientation("North-East");
			var areaGlazingEast:Number = areas.calculateTotalWindowsAreaByOrientation("East");
			var areaGlazingSouthEast:Number = areas.calculateTotalWindowsAreaByOrientation("South-East");
			var areaGlazingSouth:Number = areas.calculateTotalWindowsAreaByOrientation("South");
			var areaGlazingSouthWest:Number = areas.calculateTotalWindowsAreaByOrientation("South-West");
			var areaGlazingWest:Number = areas.calculateTotalWindowsAreaByOrientation("West");
			var areaGlazingNorthWest:Number = areas.calculateTotalWindowsAreaByOrientation("North-West");
			var areaGlazingHorizontal:Number = 0;
			
			var glazingPercentage:Number = 0.8;
			
			var gValueNorth:Number = areas.calculateMeanGValueOfWindowsByOrientation("North");
			var gValueNorthEast:Number = areas.calculateMeanGValueOfWindowsByOrientation("North-East");
			var gValueEast:Number = areas.calculateMeanGValueOfWindowsByOrientation("East");
			var gValueSouthEast:Number = areas.calculateMeanGValueOfWindowsByOrientation("South-East");
			var gValueSouth:Number = areas.calculateMeanGValueOfWindowsByOrientation("South");
			var gValueSouthWest:Number = areas.calculateMeanGValueOfWindowsByOrientation("South-West");
			var gValueWest:Number = areas.calculateMeanGValueOfWindowsByOrientation("West");
			var gValueNorthWest:Number = areas.calculateMeanGValueOfWindowsByOrientation("North-West");
			var gValueHorizontal:Number = 0;
			
			var meanShadingFactor:Number = 0.7;
			
			var correctionFactor:Number = 0.72;
			
			var globalRadHeatingTimesNorth:Number = climateZoneInfo.globalNorth;
			var globalRadHeatingTimesNorthEast:Number = (climateZoneInfo.globalNorth + climateZoneInfo.globalEast)/2;
			var globalRadHeatingTimesEast:Number = climateZoneInfo.globalEast;
			var globalRadHeatingTimesSouthEast:Number = (climateZoneInfo.globalSouth + climateZoneInfo.globalEast)/2;
			var globalRadHeatingTimesSouth:Number = climateZoneInfo.globalSouth;
			var globalRadHeatingTimesSouthWest:Number = (climateZoneInfo.globalSouth + climateZoneInfo.globalWest)/2;
			var globalRadHeatingTimesWest:Number = climateZoneInfo.globalWest;
			var globalRadHeatingTimesNorthWest:Number = (climateZoneInfo.globalWest + climateZoneInfo.globalNorth)/2;
			var globalRadHeatingTimesHorizontal:Number = areaGlazingHorizontal;
			
			var solarHeatGainsNorth:Number = areaGlazingNorth * glazingPercentage * gValueNorth * meanShadingFactor * correctionFactor * globalRadHeatingTimesNorth;
			var solarHeatGainsNorthEast:Number = areaGlazingNorthEast * glazingPercentage * gValueNorthEast * meanShadingFactor * correctionFactor * globalRadHeatingTimesNorthEast;
			var solarHeatGainsEast:Number = areaGlazingEast * glazingPercentage * gValueEast * meanShadingFactor * correctionFactor * globalRadHeatingTimesEast;
			var solarHeatGainsSouthEast:Number = areaGlazingSouthEast * glazingPercentage * gValueSouthEast * meanShadingFactor * correctionFactor * globalRadHeatingTimesSouthEast;
			var solarHeatGainsSouth:Number = areaGlazingSouth * glazingPercentage * gValueSouth * meanShadingFactor * correctionFactor * globalRadHeatingTimesSouth;
			var solarHeatGainsSouthWest:Number = areaGlazingSouthWest * glazingPercentage * gValueSouthWest * meanShadingFactor * correctionFactor * globalRadHeatingTimesSouthWest;
			var solarHeatGainsWest:Number = areaGlazingWest * glazingPercentage * gValueWest * meanShadingFactor * correctionFactor * globalRadHeatingTimesWest;
			var solarHeatGainsNorthWest:Number = areaGlazingNorthWest * glazingPercentage * gValueNorthWest * meanShadingFactor * correctionFactor * globalRadHeatingTimesNorthWest;
			var solarHeatGainsHorizontal:Number = areaGlazingHorizontal * glazingPercentage * gValueHorizontal * meanShadingFactor * correctionFactor * globalRadHeatingTimesHorizontal;
			
			return solarHeatGainsNorth + solarHeatGainsNorthEast + solarHeatGainsEast + solarHeatGainsSouthEast + solarHeatGainsSouth + solarHeatGainsSouthWest + solarHeatGainsWest + solarHeatGainsNorthWest + solarHeatGainsHorizontal;
		}
		
		public function calculateTotalHeatGains():Number
		{
			var efficiencyOfHeatGains:Number = this.internalHeatGains + this.solarHeatGains;
			var rationOfGainsToLosses:Number = efficiencyOfHeatGains/this.totalHeatLosses;
			
			var efficiencyOfHeatLosses:Number =  ((1 - Math.pow(rationOfGainsToLosses,5))/
				(1 - Math.pow(rationOfGainsToLosses,6)));
			
			return efficiencyOfHeatLosses * efficiencyOfHeatGains;
		}
		
		public function calculateAnnualHeatDemand():Number
		{
			return  this.totalHeatLosses - this.totalHeatGains;
		}
		
		public function calculateSpecificAnnualHeatDemand():Number
		{
			var totalHeatedSpaceArea:Number = this.areasController.getTotlaHeatedSpaceArea();
			
			return this.anualHeatDemand/totalHeatedSpaceArea;
		}
		
		
		
		private function calculateHeateLossesByComponentType(componentType:String, heatingHours:Number):Number
		{
			var result:Number = 0;
			var totalAreaOfComponentsOfSelectedType:Number = this.areasController.getTotalAreaOfSolidComponentsByType(componentType);
			var meanUValueOfComponentsOfSelectedType:Number = this.areasController.calculateMeanUValueOfSolidComponentsByType(componentType);
			var redFactor:Number = 1;
			
			result = totalAreaOfComponentsOfSelectedType * meanUValueOfComponentsOfSelectedType * redFactor * heatingHours;
			
			if (isNaN(result))
			{
				return 0;
			}
			else
			{
				return result;
			}
		}
		
		private function calculateHeateLossesByWindows(heatingHours:Number):Number
		{
			var result:Number = 0;
			var totalAreaOfWindows:Number = this.areasController.calculateTotalAreaOfWindows();
			var meanUValueOfWindows:Number = this.areasController.calculateMeanUValueOfWindows();
			var redFactor:Number = 1;
			
			result = totalAreaOfWindows * meanUValueOfWindows * redFactor * heatingHours;
			
			if (isNaN(result))
			{
				return 0;
			}
			else
			{
				return result;
			}
		}
		
		private function calculateHeateLossesByDoors(heatingHours:Number):Number
		{
			var result:Number = 0;
			var totalAreaOfDoors:Number = this.areasController.calculateTotalAreaOfDoors();
			var meanUValueOfDoors:Number = this.areasController.calculateMeanUValueOfDoors();
			var redFactor:Number = 1;
			
			result = totalAreaOfDoors * meanUValueOfDoors * redFactor * heatingHours;
			
			if (isNaN(result))
			{
				return 0;
			}
			else
			{
				return result;
			}
		}
	
		public function get specificAnnualHeatDemand():Number
		{
			return _specificAnnualHeatDemand;
		}

		public function set specificAnnualHeatDemand(value:Number):void
		{
			_specificAnnualHeatDemand = value;
		}

		public function get anualHeatDemand():Number
		{
			return _anualHeatDemand;
		}

		public function set anualHeatDemand(value:Number):void
		{
			_anualHeatDemand = value;
		}

		public function get totalHeatGains():Number
		{
			return _totalHeatGains;
		}

		public function set totalHeatGains(value:Number):void
		{
			_totalHeatGains = value;
		}

		public function get solarHeatGains():Number
		{
			return _solarHeatGains;
		}

		public function set solarHeatGains(value:Number):void
		{
			_solarHeatGains = value;
		}

		public function get internalHeatGains():Number
		{
			return _internalHeatGains;
		}

		public function set internalHeatGains(value:Number):void
		{
			_internalHeatGains = value;
		}

		public function get totalHeatLosses():Number
		{
			return _totalHeatLosses;
		}

		public function set totalHeatLosses(value:Number):void
		{
			_totalHeatLosses = value;
		}

		public function get ventilationHeatLosses():Number
		{
			return _ventilationHeatLosses;
		}

		public function set ventilationHeatLosses(value:Number):void
		{
			_ventilationHeatLosses = value;
		}

		public function get transmissionHeatLosses():Number
		{
			return _transmissionHeatLosses;
		}

		public function set transmissionHeatLosses(value:Number):void
		{
			_transmissionHeatLosses = value;
		}
		
		
		
	}
}